package com.ruoyi.ruoyiqywechat.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.utils.DateUtils;
import com.ruoyi.common.core.utils.JwtUtils;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.qy.domain.User;
import com.ruoyi.common.qy.exception.CrmebException;
import com.ruoyi.common.qy.oss.OssService;
import com.ruoyi.common.qy.utils.*;
import com.ruoyi.common.qy.vo.VideoInfoVo;
import com.ruoyi.common.redis.utils.RedisUtil;
import com.ruoyi.common.security.utils.SecurityUtils;
import com.ruoyi.ruoyiqywechat.aliyunconfig.SpeechFlashRecognizerDemo;
import com.ruoyi.ruoyiqywechat.domain.UserMembership;
import com.ruoyi.ruoyiqywechat.service.IUserMembershipService;
import com.ruoyi.ruoyiqywechat.service.UserService;
import com.ruoyi.ruoyiqywechat.service.VideoService;
import com.ruoyi.ruoyiqywechat.service.aliyun.AliyunService;
import com.ruoyi.ruoyiqywechat.service.py.PythonService;
import com.ruoyi.ruoyiqywechat.service.qywechat.QyMessageService;
import com.ruoyi.ruoyiqywechat.service.qywechat.config.WechatConfig;
import com.ruoyi.system.api.RemoteChanceService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

@Service
public class VideoServiceImpl implements VideoService {
    @Autowired
    private RedisUtil redisUtil;

    @Autowired
    private RemoteChanceService remoteChanceService;
    @Autowired
    private QyMessageService qyMessageService;
    @Autowired
    private WechatConfig wechatConfig;

    @Autowired
    private PythonService pythonService;
    @Autowired
    private AliyunService aliyunService;


    @Value("${videoGuid}")
    private String videoGuid;
    @Value("${qianwenSkId}")
    private String qianwenSkId;
    // 创建自定义线程池
    ExecutorService customExecutor = Executors.newFixedThreadPool(5);

    @Override
    public void saveRedisVideo(JSONObject jsonObject) {
        long startTime = System.currentTimeMillis();
        long uuid = new Date().getTime();//时间戳作为唯一id
        String objectId = jsonObject.getString("object_id");
        String objectNonceId = jsonObject.getString("object_nonce_id");
        String sender = jsonObject.getString("sender");
        String senderName = jsonObject.getString("sender_name");
        boolean b = checkUserMember(sender);
        if(!b){
            return;
        }

//
        //发送请求获取视频号信息
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        stringObjectHashMap.put("guid", videoGuid);
        stringObjectHashMap.put("object_id", objectId);
        stringObjectHashMap.put("object_nonce_id", objectNonceId);
        stringObjectHashMap.put("last_buffer", "");
        String jsonString = remoteChanceService.finderDetail(stringObjectHashMap);
        JSONObject object = JSONObject.parseObject(jsonString).getJSONObject("object");

        JSONObject objectDesc = object.getJSONObject("objectDesc");
        JSONObject media = objectDesc.getJSONArray("media").getJSONObject(0);
//        CompletableFuture.runAsync(() -> {
//            asynInfo(media, objectDesc.getString("description"), object, uuid, sender);
//        }, customExecutor);

        AtomicReference<String> result = new AtomicReference<>("");
        CompletableFuture<Void> videoFuture = CompletableFuture.runAsync(() -> {
//            result.set(handlVideoUrl(media.getString("url")));//处理视频地址并上传()
            result.set(media.getString("url").replace("http","https")+".mp4");//处理视频地址并上传()
        });
        AtomicReference<String> coverUrl = new AtomicReference<>("");
        CompletableFuture<Void> imageFuture = CompletableFuture.runAsync(() -> {
//            coverUrl.set(handlImageUrl(media.getString("coverUrl")));//处理视频地址并上传()
            try {
                coverUrl.set(media.getString("coverUrl").replace("http", "https") + ".jpg");//处理视频地址并上传()
            }catch (Exception e){
                System.out.println(uuid+"=====没有封面~");
                coverUrl.set(media.getString("thumbUrl").replace("http", "https") + ".jpg");//处理视频地址并上传()

            }
        });
        String description = objectDesc.getString("description");//标题

        AtomicReference<String> nickName = new AtomicReference<>("");
        AtomicLong likeCount = new AtomicLong();
        AtomicLong commentCount = new AtomicLong();
        AtomicLong createtime = new AtomicLong();
        AtomicReference<String> buyDateTime = new AtomicReference<>("");
        AtomicReference<LocalDateTime> buyLocalDateTime = new AtomicReference();
        CompletableFuture<Void> otherFuture = CompletableFuture.runAsync(() -> {
            nickName.set(object.getString("nickname"));//作者
            likeCount.set(object.getLongValue("likeCount"));//点赞数
            commentCount.set(object.getLongValue("commentCount"));//评论数
            createtime.set(object.getLongValue("createtime"));//评论数
            buyDateTime.set(UnixTimestampConverter.timestampToString(createtime.get()));
            buyLocalDateTime.set(StringToLocalDateTime.parseStandard(buyDateTime.get()));
        }, customExecutor);

        AtomicLong videoPlayLen = new AtomicLong();
        AtomicLong width = new AtomicLong();
        AtomicLong height = new AtomicLong();
        AtomicLong fileSize = new AtomicLong();
        AtomicReference<String> videoPlayLenStr = new AtomicReference<String>("");
        AtomicReference<String> fileSizeStr = new AtomicReference<String>("");
        CompletableFuture<Void> runAsync = CompletableFuture.runAsync(() -> {
            videoPlayLen.set(media.getLongValue("videoPlayLen"));//时长
            videoPlayLenStr.set(SecondsConverter.toChineseFormat(videoPlayLen.get()));
            width.set(media.getLongValue("width"));//时长
            height.set(media.getLongValue("height"));//时长
            fileSize.set(media.getLongValue("fileSize"));//时长
            fileSizeStr.set(new BigDecimal(ByteToMBConverter.bytesToMB(fileSize.get())).setScale(2, RoundingMode.DOWN) + "Mb");
        }, customExecutor);


        CompletableFuture<Void> voidCompletableFuture = CompletableFuture.allOf(runAsync, otherFuture, videoFuture, imageFuture);
        voidCompletableFuture.join();


//        CompletableFuture.runAsync(() -> {
        VideoInfoVo videoInfoVo = new VideoInfoVo();
        videoInfoVo.setVideoUrl(result.get());
        videoInfoVo.setTitle(description);
        videoInfoVo.setNickName(nickName.get());
        videoInfoVo.setCoverUrl(coverUrl.get());
        videoInfoVo.setVideoPlayLen(videoPlayLen.get());
        videoInfoVo.setTimeStr(videoPlayLenStr.get());
        videoInfoVo.setWidth(width.get());
        videoInfoVo.setHeight(height.get());
        videoInfoVo.setFileSize(fileSize.get());
        videoInfoVo.setFileSizeStr(fileSizeStr.get());
        videoInfoVo.setLikeCount(likeCount.get());
        videoInfoVo.setCommentCount(commentCount.get());

        videoInfoVo.setBuyDate(buyLocalDateTime.get());

        videoInfoVo.setCreatelDate(LocalDateTime.now());
        videoInfoVo.setCreateDateTime(DateUtils.getNowDate().getTime());
        videoInfoVo.setId(uuid);
        // 存储到 Redis 时，确保生成有效的 JSON
        String videoJSON = JSONObject.toJSONString(videoInfoVo);
// 检查并修复 JSON 格式
        videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
        redisUtil.set(CacheConstants.TEMP_VIDEO_CREATE_USER + uuid, videoJSON, 2l, TimeUnit.HOURS);
//        });
        long endTime = System.currentTimeMillis();

        System.out.println("总的时间：" + (endTime - startTime));
        //发送小程序的消息给回去。
        HashMap<String, Object> map = new HashMap<>();
        map.put("conversation_id", "S:" + sender);
//        map.put("conversation_id", "S:7881300404133715");慢慢
        System.out.println("当前用户的username:gh_cddddea7fea2@app");
        map.put("username", "gh_cddddea7fea2@app");
        map.put("appid", wechatConfig.getAppid());
        map.put("appname", wechatConfig.getAppname());
        map.put("appicon", wechatConfig.getAppicon());
//        map.put("title", wechatConfig.getTitle());
        String descString = objectDesc.getString("description");
        map.put("title", "[提取成功]");

        if(StringUtils.isNotBlank(descString)){
            String title = "[提取成功]" + descString;
            if(descString.length() > 5){
                // 安全截取，避免截断Unicode字符
                int endIndex = descString.offsetByCodePoints(0, 5);
                title = "[提取成功]" + descString.substring(0, endIndex) + "..";
            }
            map.put("title", title);
        }

        map.put("page_path", wechatConfig.getPage_path() + "videoId=" + uuid);//uuid作为唯一标识传参数
        map.put("file_id", wechatConfig.getFile_id());
        map.put("size", wechatConfig.getSize());
        map.put("aes_key", wechatConfig.getAes_key());
        map.put("md5", wechatConfig.getMd5());

        //是会员
        qyMessageService.send_weapp(map);
    }

    /**
     * 检查是否是会员
     * @return
     */
    public boolean checkUserMember(String sender){
        LambdaQueryWrapper<User> userLambdaQueryWrapper = new LambdaQueryWrapper<>();
        userLambdaQueryWrapper.eq(User::getTagId,sender);
        User userServiceOne = userService.getOne(userLambdaQueryWrapper);
        if(ObjectUtil.isNull(userServiceOne) || !userServiceOne.getIsFenjian()){
            //判断账号获取的总次数是否超过10次
            String cacheKey = CacheConstants.WX_WATCH_VIDEO_NUM + sender ;
            Long incr = redisUtil.incr(cacheKey, 1L);
            System.out.println("用户："+sender+"发送视频的次数"+incr);
            if(incr <= number){//免费次数
                return true;
            }else{
                //发送会员连接去绑定并支付
                HashMap<String, Object> mapMember = new HashMap<>();
                mapMember.put("conversation_id", "S:" + sender);
                mapMember.put("title", "10次免费体验已结束，会员特权待开启！");
                mapMember.put("description", "立即绑定身份，探索更多精彩内容");//uuid作为唯一标识传参数
                mapMember.put("url", "https://vx.jxhaoliu.cn/h5_litui_vip/#/pages/vip/vip?sendUserId="+sender);
                mapMember.put("image_url", "https://wx.qlogo.cn/mmhead/Q3auHgzwzM6DgpZJlicKaZGicIzF6TTAeCoTAa4VMk86MQqxLLA9tRZw/0");
                qyMessageService.send_gh(mapMember);
            }
            return false;
        }else{
            return true;
        }
    }

    @Value("${appinfo.num}")
    private int number;

    @Autowired
    private UserService userService;
    public void asynInfo(JSONObject media, String title, JSONObject object, long uuid, String sender) {
        VideoInfoVo videoInfoVo = new VideoInfoVo();
        videoInfoVo.setVideoUrl(media.getString("url")+".mp4");
        videoInfoVo.setCoverUrl(media.getString("coverUrl"));
        videoInfoVo.setTitle(title);
        videoInfoVo.setNickName(object.getString("nickname"));
        videoInfoVo.setVideoPlayLen(media.getLongValue("videoPlayLen"));
        videoInfoVo.setTimeStr(SecondsConverter.toChineseFormat(videoInfoVo.getVideoPlayLen()));
//        videoInfoVo.setWidth(width.get());
//        videoInfoVo.setHeight(height.get());
        videoInfoVo.setFileSize(media.getLongValue("fileSize"));
        videoInfoVo.setFileSizeStr(new BigDecimal(ByteToMBConverter.bytesToMB(videoInfoVo.getFileSize())).setScale(2, RoundingMode.DOWN) + "Mb");
//        videoInfoVo.setLikeCount(likeCount.get());
//        videoInfoVo.setCommentCount(commentCount.get());
        long createtime = object.getLongValue("createtime");//评论数
        String buyDateTime = UnixTimestampConverter.timestampToString(createtime);
        videoInfoVo.setBuyDate(StringToLocalDateTime.parseStandard(buyDateTime));

        videoInfoVo.setCreatelDate(LocalDateTime.now());
        videoInfoVo.setCreateDateTime(DateUtils.getNowDate().getTime());
        videoInfoVo.setId(uuid);
        // 存储到 Redis 时，确保生成有效的 JSON
        String videoJSON = JSONObject.toJSONString(videoInfoVo);
// 检查并修复 JSON 格式
        videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
        redisUtil.set(CacheConstants.TEMP_VIDEO_CREATE_USER + uuid, videoJSON, 2l, TimeUnit.HOURS);
        //发送小程序的消息给回去。
        HashMap<String, Object> map = new HashMap<>();
        map.put("conversation_id", "S:" + sender);
//        map.put("conversation_id", "S:7881300404133715");慢慢
        System.out.println("当前用户的username:gh_cddddea7fea2@app");
        map.put("username", "gh_cddddea7fea2@app");
        map.put("appid", wechatConfig.getAppid());
        map.put("appname", wechatConfig.getAppname());
        map.put("appicon", wechatConfig.getAppicon());
//        map.put("title", wechatConfig.getTitle());
        map.put("title", "[提取成功]" + title);
        map.put("page_path", wechatConfig.getPage_path() + "videoId=" + uuid);//uuid作为唯一标识传参数
        map.put("file_id", wechatConfig.getFile_id());
        map.put("size", wechatConfig.getSize());
        map.put("aes_key", wechatConfig.getAes_key());
        map.put("md5", wechatConfig.getMd5());
        qyMessageService.send_weapp(map);
    }

    public String handlVideoUrl(String url) {
        //处理地址问题，上传到oss
        String result = url.replaceAll("&basedata.*", "");
        try {
            result = OssService.uploadFileVideoFromUrl(result);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }

    public String handlImageUrl(String url) {
        //处理地址问题，上传到oss
        String result = "";
        try {
            result = OssService.uploadFileImageFromUrl(url);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return result;
    }


    @Override
    public HashMap<String, Object> listVideoInfoVo(HttpServletRequest request, int page, int size) {
        // 计算分页起始位置
        long start = (page - 1) * size;
        long end = start + size - 1;

        String token = SecurityUtils.getToken(request);
        if (StringUtils.isBlank(token)) {
            throw new CrmebException("请先登录!");
        }
        String userId = JwtUtils.getUserId(token);
        String userVideosKey = CacheConstants.VIDEO_CREATE_USER + userId;
        RedisTemplate<String, Object> redisTemplate = redisUtil.getRedisTemplate();
        // 获取总数据量
        Long totalCount = redisTemplate.opsForZSet().size(userVideosKey);
        if (totalCount == null || totalCount == 0) {
            HashMap<String, Object> stringObjectHashMap = new HashMap<>();
            stringObjectHashMap.put("total", totalCount);
            stringObjectHashMap.put("page", page);
            stringObjectHashMap.put("size", size);
            stringObjectHashMap.put("data", new ArrayList<>());
            return stringObjectHashMap;
        }

// 检查分页范围是否超出数据范围
        if (start >= totalCount) {
            HashMap<String, Object> stringObjectHashMap = new HashMap<>();
            stringObjectHashMap.put("total", totalCount);
            stringObjectHashMap.put("page", page);
            stringObjectHashMap.put("size", size);
            stringObjectHashMap.put("data", new ArrayList<>());
            return stringObjectHashMap;
        }

// 确保end不超过最大索引
        end = Math.min(end, totalCount - 1);
//        System.out.println("当前分页列表："+start+"   "+end +"   size ="+size);
        Set<ZSetOperations.TypedTuple<Object>> videoTuples = redisTemplate.opsForZSet().reverseRangeWithScores(userVideosKey, start, end);
        List<VideoInfoVo> videoDetails = new ArrayList<>();
        List<Long> videoKeysToGet = new ArrayList<>();
        // 2. 收集需要查询的 Video Key
        for (ZSetOperations.TypedTuple<Object> tuple : videoTuples) {
//            System.out.println("videoTuples的条数："+tuple.getValue());
            // tuple.getScore() 就是时间戳，如果需要可以一起返回
            videoKeysToGet.add(Long.parseLong(String.valueOf(tuple.getValue())));
        }

        // 3. 使用 multiGet 批量获取所有视频详情，避免循环内多次网络IO
        // 使用 Pipeline 性能更好，这里简化用 multiGet Hash 字段
        for (long videoKey : videoKeysToGet) {
            // 获取整个 Hash 对象
            Object videoDetail = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, String.valueOf(videoKey));
            if (videoDetail == null) {
                //删除
                redisUtil.removeElements(userVideosKey, videoKey);
                continue;
            }
            VideoInfoVo videoInfo = null;
            try {
                videoInfo = JSONObject.parseObject(videoDetail.toString(), VideoInfoVo.class);
                // 使用 videoInfo 对象
            } catch (Exception e) {
                // 处理异常或返回默认值
            }
            if (videoInfo == null) {
                continue;
            }
//            System.out.println("redis中的数据：" + videoDetail);
            videoDetails.add(videoInfo);
        }
//        videoDetails = videoDetails.stream().skip(start).limit(size).collect(Collectors.toList());
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        Long aLong = redisTemplate.opsForZSet().size(userVideosKey);
        stringObjectHashMap.put("total", aLong);
        stringObjectHashMap.put("page", page);
        stringObjectHashMap.put("size", size);
        stringObjectHashMap.put("data", videoDetails);
        return stringObjectHashMap;
    }



    @Override
    public HashMap<String, Object> queryVideoText(HttpServletRequest request, String videoId) {

        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        String token = SecurityUtils.getToken(request);
        if (StringUtils.isBlank(token)) {
            throw new CrmebException("请先登录!");
        }

        String userId = JwtUtils.getUserId(token);
//        Object videoDetail = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
//        if (videoDetail != null) {
//            VideoInfoVo videoInfo = null;
//            try {
//                videoInfo = JSONObject.parseObject(videoDetail.toString(), VideoInfoVo.class);
//                // 使用 videoInfo 对象
//            } catch (Exception e) {
//                // 处理异常或返回默认值
//            }
//            stringObjectHashMap.put("data", videoInfo);
//        }else{
        //缓存中查询视频信息
        Object o = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
        if (o == null) {
            throw new CrmebException("视频信息已过期!");
        }
        VideoInfoVo videoInfo = null;
        try {
            videoInfo = JSONObject.parseObject(o.toString(), VideoInfoVo.class);
            // 使用 videoInfo 对象
        } catch (Exception e) {
            // 处理异常或返回默认值
        }
        if (videoInfo == null) {
            throw new CrmebException("视频信息已过期!");
        }
        //音频转文字调用阿里云
//        String oldText = aliyunService.mp4toText(videoInfo.getVideoUrl());
//        System.out.println("音频转文案的结果" + oldText);

        String videoPath = videoInfo.getVideoUrl();
        String audioPath = "/mnts/jar_work/LiTui/qywechat/mp3/output_audio_"+userId+"_"+videoId+".mp3";

        String oldText = aliyunService.extractAudioFromVideo(videoPath, audioPath);
        System.out.println("音频提取成功: " + oldText);
//            String text = "儿子在学校闯祸了，老师让我去，我骗老婆说我儿子在学校得奖了，她在家化妆换衣服收拾两个多小时抢着要去，着不进去两个多小时了，现在出来了[破涕为笑]#惊不惊喜意不意外 #万万没想到#搞笑家庭";

        //生成2段文案
        ArrayList<String> arrayList = new ArrayList<>();
        arrayList.add(oldText);
//                try {
//                    CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
//                        QwenHttpClientUtils client = new QwenHttpClientUtils(qianwenSkId);
//                        // 使用qwen-plus模型
//                        String response = null;
//                        try {
//                            response = client.sendMessage(
//                                    "你是短视频文案大师，任何文案在你手里都能成为最优质的文案，需要你进行理解改成类似相近有很优质属于个人的文案，需要你进行理解改成类似相近有很优质属于个人的文案，你帮我生成3段与原视频类似的优质内容,每段内容分别采用字段title1,title2,title3，方便json对象解析，每段长度按照原来的长度进行优化即可，【】是需要你来成为优质文案的原文案。【" + oldText + "】",
//                                    "qwen-plus",
//                                    0.7,
//                                    500
//                            );
//                        } catch (Exception e) {
//                            throw new RuntimeException("语言模型调用失败!");
//                        }
//                        response = response.replace("```json", "").replace("```", "");
//                        JSONObject parsedObject = JSONObject.parseObject(response);
//                        arrayList.add(parsedObject.getString("title1"));
//                        arrayList.add(parsedObject.getString("title2"));
//                        arrayList.add(parsedObject.getString("title3"));
//
//                    });
//                    completableFuture.get();
//                }catch (Exception e){
//                    e.printStackTrace();
//                    throw new RuntimeException("文案生成失败!");
//                }
        videoInfo.setTextArr(arrayList);

        stringObjectHashMap.put("data", videoInfo);
        //视频信息存入到缓存中hash的数据结构。
        // 存储到 Redis 时，确保生成有效的 JSON
        String videoJSON = JSONObject.toJSONString(videoInfo);
        // 检查并修复 JSON 格式
        videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
        redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);

//        }
        return stringObjectHashMap;
    }

    @Override
    public HashMap<String, Object> queryVideoInfo(HttpServletRequest request, String videoId) {
        System.out.println("查询的视频id===="+videoId);
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        String userId;
        if(!"1760153033634".equals(videoId)){
            String token = SecurityUtils.getToken(request);
            if (StringUtils.isBlank(token)) {
                throw new CrmebException("请先登录!");
            }
            userId  = JwtUtils.getUserId(token);
        }else {
            userId = "1";
        }
        Object ox = redisUtil.get(CacheConstants.TEMP_VIDEO_CREATE_USER + videoId);
        VideoInfoVo videoInfoTemp = null;
        if (ox != null) {
            try {
                videoInfoTemp = JSONObject.parseObject(ox.toString(), VideoInfoVo.class);
                // 使用 videoInfo 对象
            } catch (Exception e) {
                // 处理异常或返回默认值
            }
        }

        //缓存中查询视频信息
        Object o = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
        if (o == null) {
            stringObjectHashMap.put("data", videoInfoTemp);
            // 存储到 Redis 时，确保生成有效的 JSON
            String videoJSON = JSONObject.toJSONString(videoInfoTemp);
            // 检查并修复 JSON 格式
            videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
            redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);
            return stringObjectHashMap;
        }
        VideoInfoVo videoInfo = null;
        try {
            videoInfo = JSONObject.parseObject(o.toString(), VideoInfoVo.class);
            if (videoInfoTemp.getVideoUrl().lastIndexOf(".mp4") != -1) {
                videoInfo.setVideoUrl(videoInfoTemp.getVideoUrl());
                videoInfo.setCoverUrl(videoInfoTemp.getCoverUrl());
            }
            // 使用 videoInfo 对象
        } catch (Exception e) {
            // 处理异常或返回默认值
        }
        if (videoInfo == null) {
            throw new CrmebException("视频信息已过期!");
        }
        // 存储到 Redis 时，确保生成有效的 JSON
        String videoJSON = JSONObject.toJSONString(videoInfo);
        // 检查并修复 JSON 格式
        videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
        redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);
        stringObjectHashMap.put("data", videoInfo);
        return stringObjectHashMap;
    }

    @Override
    public String queryRestVideoText(HttpServletRequest request, String videoId) {
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        String token = SecurityUtils.getToken(request);
        if (StringUtils.isBlank(token)) {
            throw new CrmebException("请先登录!");
        }

        String userId = JwtUtils.getUserId(token);
//        Object videoDetail = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
//        if (videoDetail != null) {
//            VideoInfoVo videoInfo = null;
//            try {
//                videoInfo = JSONObject.parseObject(videoDetail.toString(), VideoInfoVo.class);
//                // 使用 videoInfo 对象
//            } catch (Exception e) {
//                // 处理异常或返回默认值
//            }
//            stringObjectHashMap.put("data", videoInfo);
//        }else{

        //缓存中查询视频信息
        Object o = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
        if (o == null) {
            throw new CrmebException("视频信息已过期!");
        }
        VideoInfoVo videoInfo = null;
        try {
            videoInfo = JSONObject.parseObject(o.toString(), VideoInfoVo.class);
            // 使用 videoInfo 对象
        } catch (Exception e) {
            // 处理异常或返回默认值
        }
        if (videoInfo == null) {
            throw new CrmebException("视频信息已过期!");
        }
        List<String> textArr = videoInfo.getTextArr();
        //根据原文案重新输出
        if (textArr != null && !CollectionUtils.isEmpty(textArr)) {
            String oldText = textArr.get(0);
            //生成1段文案
            try {
                CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                    QwenHttpClientUtils client = new QwenHttpClientUtils(qianwenSkId);
                    // 使用qwen-plus模型
                    String response = null;
                    try {
                        response = client.sendMessage(
                                "你是短视频文案大师，请基于以下初始原文案开展核心工作：【】。【" + oldText + "】"+
                                        "配套分析框架参考：基础层（核心属性 + 受众）、核心层（主题 + 结构 + 语言）、落地层（数据目标：播放量，点赞量， + 关联逻辑）\n" +
                                        "在文案库中检索出与原文案基础层相同的，且最合适的两篇文案并且每篇文案" +
                                        "字数与原文字数保持一致，不漏字，现在你帮我生成一段与原视频类似的优质内容，生成的每段完整内容分别采用字段title1，" +
                                        "方便json对象解析。",
                                "qwen-plus",
                                0.7,
                                500000
                        );
                    } catch (Exception e) {
                        throw new RuntimeException("语言模型调用失败!");
                    }
                    response = response.replace("```json", "").replace("```", "");
                    System.out.println("返回值："+response);
                    JSONObject parsedObject = JSONObject.parseObject(response);
                    textArr.add(parsedObject.getString("title1"));
                });
                completableFuture.get();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("文案生成失败!");
            }
            videoInfo.setTextArr(textArr);
            stringObjectHashMap.put("data", videoInfo);
            //视频信息存入到缓存中hash的数据结构。
            // 存储到 Redis 时，确保生成有效的 JSON
            String videoJSON = JSONObject.toJSONString(videoInfo);
            // 检查并修复 JSON 格式
            videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
            redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);
            return textArr.get(textArr.size() - 1);
        }
        return null;
    }

    @Autowired
    private IUserMembershipService userMembershipService;
    @Override
    public Boolean queryWatchVideoNum(HttpServletRequest request, String videoId, String type) {
        Long userId = SecurityUtils.getUserId();
        // 使用当天日期作为key的一部分，确保每天自动刷新
        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String cacheKey = CacheConstants.WATCH_VIDEO_NUM + userId + ":" + type + ":" + videoId + ":" + today;
        Long watchCount = redisUtil.incr(cacheKey, 1L);
        Long decr = redisUtil.decr(cacheKey, 1L);
        System.out.println("用户："+userId+""+videoId+"观看次数"+decr);
        //判断当前是否是会员
        //判断当前会员是否重复，如果是则不允许重复会员充值
        QueryWrapper<UserMembership> userMembershipQueryWrapper = new QueryWrapper<>();
        userMembershipQueryWrapper.lambda().eq(UserMembership::getUserId,userId)
                .eq(UserMembership::getStatus,1);
        UserMembership one = userMembershipService.getOne(userMembershipQueryWrapper);
        if(one != null){
            return false;
        }

        return decr <= 0;
    }

    @Override
    public void addWatchVideoNum(HttpServletRequest request, String videoId, String type) {
        Long userId = SecurityUtils.getUserId();
        // 使用当天日期作为key的一部分，确保每天自动刷新
        String today = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String cacheKey = CacheConstants.WATCH_VIDEO_NUM + userId + ":" + type + ":" + videoId + ":" + today;
        Long watchCount = redisUtil.incr(cacheKey, 1L);
        if (watchCount == 1) {//只需要当初为1的时候设置一次即可。
            // 设置到当天结束的过期时间
            long expireSeconds = getRemainingSecondsToday();
            redisUtil.expire(cacheKey, expireSeconds);
        }
    }

    /**
     * 获取今天剩余的秒数
     */
    private long getRemainingSecondsToday() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime endOfDay = now.toLocalDate().atTime(23, 59, 59);
        return Duration.between(now, endOfDay).getSeconds();
    }

    @Override
    public List<String> queryRestVideoTextNew(HttpServletRequest request, String videoId) {
        HashMap<String, Object> stringObjectHashMap = new HashMap<>();
        String token = SecurityUtils.getToken(request);
        if (StringUtils.isBlank(token)) {
            throw new CrmebException("请先登录!");
        }

        String userId = JwtUtils.getUserId(token);
//        Object videoDetail = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
//        if (videoDetail != null) {
//            VideoInfoVo videoInfo = null;
//            try {
//                videoInfo = JSONObject.parseObject(videoDetail.toString(), VideoInfoVo.class);
//                // 使用 videoInfo 对象
//            } catch (Exception e) {
//                // 处理异常或返回默认值
//            }
//            stringObjectHashMap.put("data", videoInfo);
//        }else{

        ArrayList<String> stringArrayList = new ArrayList<>();
        //缓存中查询视频信息
        Object o = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
        if (o == null) {
            throw new CrmebException("视频信息已过期!");
        }
        VideoInfoVo videoInfo = null;
        try {
            videoInfo = JSONObject.parseObject(o.toString(), VideoInfoVo.class);
            // 使用 videoInfo 对象
        } catch (Exception e) {
            // 处理异常或返回默认值
        }
        if (videoInfo == null) {
            throw new CrmebException("视频信息已过期!");
        }
        List<String> textArr = videoInfo.getTextArr();
        //根据原文案重新输出
        if (textArr != null && !CollectionUtils.isEmpty(textArr)) {
            String oldText = textArr.get(0);
            //生成1段文案
            try {
                CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(() -> {
                    QwenHttpClientUtils client = new QwenHttpClientUtils(qianwenSkId);
                    // 使用qwen-plus模型
                    String response = null;
                    try {
                        response = client.sendMessage(
                                "你是短视频文案大师，任何文案在你手里都能生成最优质的原创文案，需要你进行理解改成字数不变的情况下生成优质原创文案，你帮我生成二段原创文案,每段内容分别采用字段title1,title2,方便json对象解析，严格保证字数不变的情况下，【】是需要你来成为优质文案的原始文案。【" + oldText + "】",
                                "qwen-plus",
                                0.7,
                                500
                        );
                    } catch (Exception e) {
                        throw new RuntimeException("语言模型调用失败!");
                    }
                    response = response.replace("```json", "").replace("```", "");
//                    System.out.println("顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶顶返回值："+response);
                    JSONObject parsedObject = JSONObject.parseObject(response);
                    textArr.add(parsedObject.getString("title1"));
                    textArr.add(parsedObject.getString("title2"));
                    stringArrayList.add(parsedObject.getString("title1"));
                    stringArrayList.add(parsedObject.getString("title2"));
                });
                completableFuture.get();
            } catch (Exception e) {
                e.printStackTrace();
                throw new RuntimeException("文案生成失败!");
            }
            videoInfo.setTextArr(textArr);
            stringObjectHashMap.put("data", videoInfo);
            //视频信息存入到缓存中hash的数据结构。
            // 存储到 Redis 时，确保生成有效的 JSON
            String videoJSON = JSONObject.toJSONString(videoInfo);
            // 检查并修复 JSON 格式
            videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
            redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);
        }
        return stringArrayList;
    }

    @Override
    public void bindVideoId(HttpServletRequest request, String videoId) {
        System.out.println("绑定视频进来：...."+videoId);
        String token = SecurityUtils.getToken(request);
        if (StringUtils.isBlank(token)) {
            throw new CrmebException("请先登录!");
        }
        String userId = JwtUtils.getUserId(token);
        Object o = redisUtil.get(CacheConstants.TEMP_VIDEO_CREATE_USER + videoId);
        if (o == null) {
            throw new CrmebException("视频信息已过期!");
        }
        VideoInfoVo videoInfo = null;
        try {
            videoInfo = JSONObject.parseObject(o.toString(), VideoInfoVo.class);
            // 使用 videoInfo 对象
        } catch (Exception e) {
            // 处理异常或返回默认值
        }
        if (videoInfo == null) {
            System.out.println("视频信息也过期");
            return;
        }
        Object hget = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
        if (hget != null) {
            try {
                videoInfo = JSONObject.parseObject(o.toString(), VideoInfoVo.class);
                if (videoInfo.getVideoUrl().lastIndexOf(".mp4") != -1) {
//                    return;
                }
                // 使用 videoInfo 对象
            } catch (Exception e) {
                // 处理异常或返回默认值
            }

        }
        // 存储到 Redis 时，确保生成有效的 JSON
        String videoJSON = JSONObject.toJSONString(videoInfo);
        // 检查并修复 JSON 格式
        videoJSON = videoJSON.replace("\n", "").replace("\r", ""); // 移除换行符
        redisUtil.zAdd(CacheConstants.VIDEO_CREATE_USER + userId, Long.parseLong(videoId), DateUtils.getNowDate().getTime());
        redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);

        //同时关联userid和videoid
//        redisUtil.set(CacheConstants.TEMP_VIDEO_URL_USER+DateUtils.getNowDate().getTime(),userId+"*"+videoId);
    }

    ExecutorService executor = Executors.newFixedThreadPool(
            Math.min(10, Runtime.getRuntime().availableProcessors() * 2)
    );

    /**
     * 每5秒执行一次视频处理
     * cron表达式说明：秒 分 时 日 月 周
     */
//    @Scheduled(cron = "*/5 * * * * ?")  // 每5秒执行一次
//    public void processVideoEvery5Seconds() {
//        System.out.println("定时任务绑定功能启动视频和封面上传oss");
//        Set<String> keys = redisUtil.getRedisTemplate().keys(CacheConstants.TEMP_VIDEO_URL_USER + "*");
//        keys.stream()
//                .map(key -> CompletableFuture.runAsync(() -> processSingleKey(key), executor))
//                .collect(Collectors.toList());
//    }
    private void processSingleKey(String key) {
        try {
            Object ox = redisUtil.get(key);
            if (ox != null) {
                String[] split = ox.toString().split("\\*");
                String userId = split[0];
                String videoId = split[1];

                Object o = redisUtil.get(CacheConstants.TEMP_VIDEO_CREATE_USER + videoId);
                if (o == null) {
                    System.out.println(Thread.currentThread().getName() + " - 视频信息也过期");
                    return;
                }

                VideoInfoVo videoInfo = parseVideoInfo(o.toString());
                if (videoInfo == null) {
                    System.out.println(Thread.currentThread().getName() + " - 视频信息也过期");
                    return;
                }

                // 防止出现再次覆盖已有的值
                Object hget = redisUtil.hget(CacheConstants.VIDEO_HASH_USER + userId, videoId);
                if (hget != null) {
                    VideoInfoVo videoInfoHash = parseVideoInfo(o.toString());
                    if (videoInfoHash != null) {
                        String videoUrl = videoInfo.getVideoUrl();
                        String coverUrl = videoInfo.getCoverUrl();

                        if (videoUrl.lastIndexOf(".mp4") < 0) {
                            videoUrl = handlVideoUrl(videoUrl);
                            coverUrl = handlImageUrl(coverUrl);

                            videoInfoHash.setVideoUrl(videoUrl);
                            videoInfoHash.setCoverUrl(coverUrl);

                            String videoJSON = JSONObject.toJSONString(videoInfoHash)
                                    .replace("\n", "").replace("\r", "");

                            redisUtil.hset(CacheConstants.VIDEO_HASH_USER + userId, videoId, videoJSON);
                            Long l = redisUtil.removeElements(key);
                            System.out.println(Thread.currentThread().getName() + " - 删除了：" + l);
                        }
                    }
                }
            }
        } catch (Exception e) {
            System.err.println(Thread.currentThread().getName() + " - 处理key " + key + " 时发生错误: " + e.getMessage());
        }
    }

    private VideoInfoVo parseVideoInfo(String jsonStr) {
        try {
            return JSONObject.parseObject(jsonStr, VideoInfoVo.class);
        } catch (Exception e) {
            return null;
        }
    }
}
